package com.kx.demo.jdk.collection;

import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

/**
 * @author kx
 * @date 2020/4/11
 */
public class KxArrayList<E> implements List<E>, java.io.Serializable {

    transient int size = 0;

    private static int DEFAULT_LENGTH = 10;

    private static Object[] DEFAULT_ELEMENT_DATA = {};

    private Object[] elements;

    public KxArrayList() {
        this.elements = DEFAULT_ELEMENT_DATA;
    }

    public KxArrayList(int capacity) {
        if (capacity > 0) {
            this.elements = new Object[capacity];
        } else if (capacity == 0) {
            this.elements = DEFAULT_ELEMENT_DATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: " + capacity);
        }

    }

    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public boolean contains(Object o) {
        if (size == 0 || o == null) {
            return false;
        }
        for (Object element : elements) {
            if (elements.equals(o)) {
                return true;
            }
        }
        return false;
    }

    public Iterator<E> iterator() {
        return null;
    }

    public Object[] toArray() {
        return Arrays.copyOf(elements, size);
    }

    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
        if (a.length < size) {
            return (T[]) Arrays.copyOf(elements, size, a.getClass());
        }
        System.arraycopy(elements, 0, a, 0, size);
        if (a.length > size) {
            a[size] = null;
        }
        return a;
    }

    public boolean add(E e) {
        ensureCapacityInternal(size + 1);
        elements[size++] = e;
        return true;
    }

    private void ensureCapacityInternal(int minCapacity) {
        minCapacity = calculateCapacity(minCapacity);
        int length = elements.length;
        if (length < minCapacity) {
            grow(minCapacity);
        }
    }

    private int calculateCapacity(int minCapacity) {
        if (elements == DEFAULT_ELEMENT_DATA) {
            return Math.max(DEFAULT_LENGTH, minCapacity);
        }
        return minCapacity;
    }

    private void grow(int minCapacity) {
        int oldCapacity = elements.length;
        int expectedLength = oldCapacity + (oldCapacity >> 1);
        if (expectedLength < minCapacity) {
            expectedLength = minCapacity;
        }
        if (expectedLength < 0) {
            throw new OutOfMemoryError();
        }
//        Object[] newObjects = new Object[expectedLength];
//        System.arraycopy(elements, 0, newObjects, 0, size);
//        this.elements = newObjects;
        elements = Arrays.copyOf(elements, expectedLength);
    }

    @Override
    public boolean remove(Object o) {
        int index = indexOf(o);
        if (index < 0) {
            return false;
        }

        System.arraycopy(elements, index + 1, elements, index, size - index - 1);
        elements[--size] = null;
        return true;
    }

    public boolean containsAll(Collection<?> c) {
        return false;
    }

    public boolean addAll(Collection<? extends E> c) {
        if (c == null || c.isEmpty()) {
            return false;
        }
        ensureCapacityInternal(size + c.size());
        Object[] addObjects = c.toArray();
        System.arraycopy(addObjects, 0, elements, size, addObjects.length);
        size += addObjects.length;
        return true;
    }

    public boolean addAll(int index, Collection<? extends E> c) {
        if (index < 0 || index >= size || c == null || c.isEmpty()) {
            return false;
        }
        ensureCapacityInternal(size + c.size());
        Object[] addObjects = c.toArray();
        System.arraycopy(elements, index, elements, index + addObjects.length, size - index);
        System.arraycopy(addObjects, 0, elements, index, addObjects.length);
        size += addObjects.length;
        return true;
    }

    public boolean removeAll(Collection<?> c) {
        return false;
    }

    public boolean retainAll(Collection<?> c) {
        return false;
    }

    public void clear() {

    }

    public E get(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException();
        }
        return (E) elements[index];
    }


    public E set(int index, E element) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException();
        }
        elements[index] = element;
        return element;
    }

    public void add(int index, E element) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException();
        }
        ensureCapacityInternal(size + 1);

        System.arraycopy(elements, index, elements, index + 1, size - index);
        elements[index] = element;
        size++;
    }

    public E remove(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException();
        }
        E element = elements(index);
        System.arraycopy(elements, index + 1, elements, index, size - index - 1);
        elements[--size] = null;
        return element;
    }

    private E elements(int index) {
        return (E) elements[index];
    }

    public int indexOf(Object o) {
        int index = -1;
        if (o == null || size == 0) {
            return -1;
        }
        for (int i = 0; i < size; i++) {
            if (o.equals(elements[i])) {
                index = i;
                break;
            }
        }
        return index;
    }

    public int lastIndexOf(Object o) {
        int index = -1;
        if (o == null || size == 0) {
            return -1;
        }
        for (int i = 0; i < size; i++) {
            if (o.equals(elements[i])) {
                index = i;
            }
        }
        return index;
    }

    public ListIterator<E> listIterator() {
        return null;
    }

    public ListIterator<E> listIterator(int index) {
        return null;
    }

    public List<E> subList(int fromIndex, int toIndex) {
        return null;
    }

    @Override
    public String toString() {
        if (size == 0)
            return "[]";

        StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (int i = 0; i < size - 1; i++) {
            sb.append(elements[i]);
            sb.append(", ");
        }
        sb.append(elements[size - 1]);
        return sb.append(']').toString();
    }
}

